#ifndef DESCRIPTORTABLES_H
#define DESCRIPTORTABLES_H

class InterruptServiceRoutine;

#include <Globals.h>

struct gdt_entry
{
  u16int limit_low;
  u16int base_low;
  u8int  base_middle;
  u8int  access;
  u8int  granularity;
  u8int  base_high;
} __attribute__((packed));

typedef struct gdt_entry GdtEntry;

struct gdt_ptr
{
  u16int limit;
  u32int base;
} __attribute__((packed));

typedef struct gdt_ptr GdtPtr;

struct idt_entry
{
  u16int base_lo;
  u16int sel;
  u8int  always0;
  u8int  flags;
  u16int base_hi;
} __attribute__((packed));

typedef struct idt_entry IdtEntry;

struct idt_ptr
{
  u16int limit;
  u32int base;
} __attribute__((packed));

typedef struct idt_ptr IdtPtr;

struct tss_entry
{
	u32int prev_tss;
	u32int esp0;
	u32int ss0;
	u32int esp1;
	u32int ss1;
	u32int esp2;
	u32int ss2;
	u32int cr3;
	u32int eip;
	u32int eflags;
	u32int eax;
	u32int ecx;
	u32int edx;
	u32int ebx;
	u32int esp;
	u32int ebp;
	u32int esi;
	u32int edi;
	u32int es;
	u32int cs;
	u32int ss;
	u32int ds;
	u32int fs;
	u32int gs;
	u32int ldt;
	u16int trap;
	u16int iomap_base;
} __attribute__((packed));

typedef struct tss_entry TssEntry;

/**
	@author James Molloy <james@jamesmolloy.co.uk>
*/
class DescriptorTables
{
public:
  DescriptorTables();

  ~DescriptorTables();

  /**
    Initialise the global descriptor table
  **/
  void initGdt();
  
  /**
    Initialise the interrupt descriptor table
  **/
  void initIdt();
  
  /**
    Initialise the IRQ table and remap the PIC
  **/
  void initIrq();
  
  /**
    Initialise the  model specific registers for sysenter/sysexit.
  **/
  void initSyscalls();
  
  
  /**
    Register an interrupt handler
  **/
  void registerIsr(u8int iNum, InterruptServiceRoutine *r)
  {
    interruptRoutines[iNum] = r;
  }
  
  /**
    Unregister an interrupt handler
  **/
  void unregisterIsr(u8int iNum)
  {
    interruptRoutines[iNum] = NULL;
  }
  
  /**
    Register an IRQ handler
  **/
  void registerIrq(u8int iNum, InterruptServiceRoutine *r)
  {
    interruptRoutines[iNum+32] = r;
  }
  
  /**
    Unregister an IRQ handler
  **/
  void unregisterIrq(u8int iNum)
  {
    interruptRoutines[iNum+32] = NULL;
  }

  /**
    Accessor for interruptRoutines
  **/
  InterruptServiceRoutine *getIsr(u8int n)
  {
    return interruptRoutines[n];
  }
  
  /**
    Change the kernel stack value in the TSS.
  **/
  void setKernelStack(Address stack);

private:
  void gdtSetGate(s32int num, u32int base, u32int limit, u8int access, u8int gran);
  void writeTss(s32int num, u16int ss0, u32int esp0, u16int iomap_base);

  void idtSetGate(u8int num, u32int base, u16int sel, u8int flags);

  GdtEntry gdtEntry[6];
  GdtPtr   gdtPtr;
  
  IdtEntry idtEntry[256];
  IdtPtr   idtPtr;
  
  TssEntry tssEntry;
  
  InterruptServiceRoutine *interruptRoutines[256];
  
};

extern "C"
{

extern void irq0  ();
extern void irq1  ();
extern void irq2  ();
extern void irq3  ();
extern void irq4  ();
extern void irq5  ();
extern void irq6  ();
extern void irq7  ();
extern void irq8  ();
extern void irq9  ();
extern void irq10  ();
extern void irq11  ();
extern void irq12  ();
extern void irq13  ();
extern void irq14  ();
extern void irq15  ();

extern void isr0  ();
extern void isr1  ();
extern void isr2  ();
extern void isr3  ();
extern void isr4  ();
extern void isr5  ();
extern void isr6  ();
extern void isr7  ();
extern void isr8  ();
extern void isr9  ();
extern void isr10  ();
extern void isr11  ();
extern void isr12  ();
extern void isr13  ();
extern void isr14  ();
extern void isr15  ();
extern void isr16  ();
extern void isr17  ();
extern void isr18  ();
extern void isr19  ();
extern void isr20  ();
extern void isr21  ();
extern void isr22  ();
extern void isr23  ();
extern void isr24  ();
extern void isr25  ();
extern void isr26  ();
extern void isr27  ();
extern void isr28  ();
extern void isr29  ();
extern void isr30  ();
extern void isr31  ();
// extern void isr32  ();
// extern void isr33  ();
// extern void isr34  ();
// extern void isr35  ();
// extern void isr36  ();
// extern void isr37  ();
// extern void isr38  ();
// extern void isr39  ();
// extern void isr40  ();
// extern void isr41  ();
// extern void isr42  ();
// extern void isr43  ();
// extern void isr44  ();
// extern void isr45  ();
// extern void isr46  ();
// extern void isr47  ();
// extern void isr48  ();
// extern void isr49  ();
extern void isr50  ();
extern void isr51  ();
// extern void isr52  ();
// extern void isr53  ();
// extern void isr54  ();
// extern void isr55  ();
// extern void isr56  ();
// extern void isr57  ();
// extern void isr58  ();
// extern void isr59  ();
// extern void isr60  ();
// extern void isr61  ();
// extern void isr62  ();
// extern void isr63  ();
// extern void isr64  ();
// extern void isr65  ();
// extern void isr66  ();
// extern void isr67  ();
// extern void isr68  ();
// extern void isr69  ();
// extern void isr70  ();
// extern void isr71  ();
// extern void isr72  ();
// extern void isr73  ();
// extern void isr74  ();
// extern void isr75  ();
// extern void isr76  ();
// extern void isr77  ();
// extern void isr78  ();
// extern void isr79  ();
// extern void isr80  ();
// extern void isr81  ();
// extern void isr82  ();
// extern void isr83  ();
// extern void isr84  ();
// extern void isr85  ();
// extern void isr86  ();
// extern void isr87  ();
// extern void isr88  ();
// extern void isr89  ();
// extern void isr90  ();
// extern void isr91  ();
// extern void isr92  ();
// extern void isr93  ();
// extern void isr94  ();
// extern void isr95  ();
// extern void isr96  ();
// extern void isr97  ();
// extern void isr98  ();
extern void isr99  ();
// extern void isr100 ();
// extern void isr101 ();
// extern void isr102 ();
// extern void isr103 ();
// extern void isr104 ();
// extern void isr105 ();
// extern void isr106 ();
// extern void isr107 ();
// extern void isr108 ();
// extern void isr109 ();
// extern void isr110 ();
// extern void isr111 ();
// extern void isr112 ();
// extern void isr113 ();
// extern void isr114 ();
// extern void isr115 ();
// extern void isr116 ();
// extern void isr117 ();
// extern void isr118 ();
// extern void isr119 ();
// extern void isr120 ();
// extern void isr121 ();
// extern void isr122 ();
// extern void isr123 ();
// extern void isr124 ();
// extern void isr125 ();
// extern void isr126 ();
// extern void isr127 ();
// extern void isr128 ();
// extern void isr129 ();
// extern void isr130 ();
// extern void isr131 ();
// extern void isr132 ();
// extern void isr133 ();
// extern void isr134 ();
// extern void isr135 ();
// extern void isr136 ();
// extern void isr137 ();
// extern void isr138 ();
// extern void isr139 ();
// extern void isr140 ();
// extern void isr141 ();
// extern void isr142 ();
// extern void isr143 ();
// extern void isr144 ();
// extern void isr145 ();
// extern void isr146 ();
// extern void isr147 ();
// extern void isr148 ();
// extern void isr149 ();
// extern void isr150 ();
// extern void isr151 ();
// extern void isr152 ();
// extern void isr153 ();
// extern void isr154 ();
// extern void isr155 ();
// extern void isr156 ();
// extern void isr157 ();
// extern void isr158 ();
// extern void isr159 ();
// extern void isr160 ();
// extern void isr161 ();
// extern void isr162 ();
// extern void isr163 ();
// extern void isr164 ();
// extern void isr165 ();
// extern void isr166 ();
// extern void isr167 ();
// extern void isr168 ();
// extern void isr169 ();
// extern void isr170 ();
// extern void isr171 ();
// extern void isr172 ();
// extern void isr173 ();
// extern void isr174 ();
// extern void isr175 ();
// extern void isr176 ();
// extern void isr177 ();
// extern void isr178 ();
// extern void isr179 ();
// extern void isr180 ();
// extern void isr181 ();
// extern void isr182 ();
// extern void isr183 ();
// extern void isr184 ();
// extern void isr185 ();
// extern void isr186 ();
// extern void isr187 ();
// extern void isr188 ();
// extern void isr189 ();
// extern void isr190 ();
// extern void isr191 ();
// extern void isr192 ();
// extern void isr193 ();
// extern void isr194 ();
// extern void isr195 ();
// extern void isr196 ();
// extern void isr197 ();
// extern void isr198 ();
// extern void isr199 ();
// extern void isr200 ();
// extern void isr201 ();
// extern void isr202 ();
// extern void isr203 ();
// extern void isr204 ();
// extern void isr205 ();
// extern void isr206 ();
// extern void isr207 ();
// extern void isr208 ();
// extern void isr209 ();
// extern void isr210 ();
// extern void isr211 ();
// extern void isr212 ();
// extern void isr213 ();
// extern void isr214 ();
// extern void isr215 ();
// extern void isr216 ();
// extern void isr217 ();
// extern void isr218 ();
// extern void isr219 ();
// extern void isr220 ();
// extern void isr221 ();
// extern void isr222 ();
// extern void isr223 ();
// extern void isr224 ();
// extern void isr225 ();
// extern void isr226 ();
// extern void isr227 ();
// extern void isr228 ();
// extern void isr229 ();
// extern void isr230 ();
// extern void isr231 ();
// extern void isr232 ();
// extern void isr233 ();
// extern void isr234 ();
// extern void isr235 ();
// extern void isr236 ();
// extern void isr237 ();
// extern void isr238 ();
// extern void isr239 ();
// extern void isr240 ();
// extern void isr241 ();
// extern void isr242 ();
// extern void isr243 ();
// extern void isr244 ();
// extern void isr245 ();
// extern void isr246 ();
// extern void isr247 ();
// extern void isr248 ();
// extern void isr249 ();
// extern void isr250 ();
// extern void isr251 ();
// extern void isr252 ();
// extern void isr253 ();
// extern void isr254 ();
// extern void isr255 ();
}
#endif
